package stmsv

import (
	"database/sql"
	"go.uber.org/zap"
	"sync"
	"wzgames/internal/admin/adc"
	"wzgames/internal/admin/admindao"
	"wzgames/internal/admin/api/wzabind"
	"wzgames/internal/admin/model"
	"wzgames/internal/constant"
	"wzgames/internal/gdao/aviatordao"
	"wzgames/internal/gdao/roudao"
	"wzgames/internal/gdao/stmdao"
	"wzgames/internal/gdao/walletdao"
	"wzgames/internal/gloader"
	"wzgames/internal/model/aviatorp"
	"wzgames/internal/model/roulettep"
	"wzgames/internal/model/statement"
	"wzgames/internal/model/user"
	"wzgames/internal/response"
	"wzgames/pkg/components/mysql"
	"wzgames/pkg/logger"
)

var (
	stmSv *StmSV
	once  sync.Once
)

type StmSV struct {
	walletDs  *mysql.DS
	aviatorDs *mysql.DS
	stmDs     *mysql.DS
	rouDs     *mysql.DS
}

func SV() *StmSV {
	if stmSv == nil {
		once.Do(func() {
			stmSv = &StmSV{}
			stmSv.walletDs = gloader.CommMgr().GetDBProxy(constant.MysqlOfWallet)
			stmSv.aviatorDs = gloader.CommMgr().GetDBProxy(constant.MysqlOfAviator)
			stmSv.stmDs = gloader.CommMgr().GetDBProxy(constant.MysqlOfBHistory)
			stmSv.rouDs = gloader.CommMgr().GetDBProxy(constant.MysqlOfRoulette)
		})
	}
	return stmSv
}

func (sv *StmSV) GetBetPendingUnCheck(adm *adc.Admin, req wzabind.BetPendingSsReq) ([]*user.WalletBetPending, int, int16) {
	dao := admindao.WalletDao{Driver: sv.walletDs.Ds()}
	count, e := dao.GetBetPendingCount(req)
	if e != nil {
		return nil, 0, response.ErrInternal
	}
	offset := (req.Page - 1) * req.PageSize
	ret, err := dao.GetBetPendingByCond(req, offset)
	if err != nil {
		if err != sql.ErrNoRows {
			logger.Error("[StmSV] get bet pending uncheck Error on GetBetPendingByCond", zap.Int64("AdminId", adm.AdminId()), zap.Error(err))
			return nil, 0, response.ErrInternal
		}
	}

	return ret, count, 0
}

func (sv *StmSV) GetBetPendingUnCheckList(adminId int64, req wzabind.BetPendingSsReq) ([]*user.WalletBetPending, int16) {
	dao := admindao.WalletDao{Driver: sv.walletDs.Ds()}
	offset := (req.Page - 1) * req.PageSize
	ret, err := dao.GetBetPendingByCond(req, offset)
	if err != nil {
		if err != sql.ErrNoRows {
			logger.Error("[StmSV] get bet pending uncheck list Error on GetBetPendingByCond", zap.Int64("AdminId", adminId), zap.Error(err))
			return nil, response.ErrInternal
		}
	}

	return ret, 0
}

func (sv *StmSV) GetBetPendingUnCheckCount(req wzabind.BetPendingSsReq) (int, int16) {
	dao := admindao.WalletDao{Driver: sv.walletDs.Ds()}
	count, e := dao.GetBetPendingCount(req)
	if e != nil {
		return 0, response.ErrInternal
	}

	return count, 0
}

func (sv *StmSV) GetGameBetPendingRounds(gameId int32, limit int64) ([]*model.BetPendingGroup, int16) {
	dao := admindao.WalletDao{Driver: sv.walletDs.Ds()}
	rounds, e := dao.GetGameBetPending(gameId, limit)
	if e != nil {
		return nil, response.ErrInternal
	}

	return rounds, 0
}

func (sv *StmSV) GetAviatorRound(roundId, instId int64) (*aviatorp.AviatorRoundEntity, int16) {
	dao := aviatordao.AviatorDao{Driver: sv.aviatorDs.Ds()}
	ret, e := dao.GetAvtRound(roundId, instId)
	if e != nil {
		if e != sql.ErrNoRows {
			return nil, response.ErrInternal
		}
		return nil, response.ErrNotFound
	}

	return ret, 0
}

func (sv *StmSV) GetAviatorNodeRound(nodeId, instId, roundId int64) (*aviatorp.AvtNodeRoundEntity, int16) {
	dao := aviatordao.AviatorDao{Driver: sv.aviatorDs.Ds()}
	ret, e := dao.GetAvtNodeRound(nodeId, instId, roundId)
	if e != nil {
		if e != sql.ErrNoRows {
			return nil, response.ErrInternal
		}
		return nil, response.ErrNotFound
	}

	return ret, 0
}

func (sv *StmSV) GetBetPendingIn(ids string) (map[uint64]*user.WalletBetPending, int, int16) {
	dao := admindao.WalletDao{Driver: sv.walletDs.Ds()}
	ret, count, e := dao.GetBetPendingIn(ids)
	if e != nil {
		if e != sql.ErrNoRows {
			return nil, 0, response.ErrInternal
		}
	}

	return ret, count, 0
}

func (sv *StmSV) GetBetPending(betId uint64) (*user.WalletBetPending, int16) {
	dao := walletdao.WalletDao{Driver: sv.walletDs.Ds()}
	ret, e := dao.GetBetPending(betId)
	if e != nil {
		if e != sql.ErrNoRows {
			return nil, response.ErrInternal
		}
		return nil, response.ErrNotFound
	}

	return ret, 0
}

func (sv *StmSV) GetBetPendingStepInfo(betId uint64) (*statement.PlayPayoutEnt, *statement.PlayStepEnt, int16) {
	dao := stmdao.StmDao{Driver: sv.stmDs.Ds()}
	payoutEx, e := dao.GetPlayPayout(betId)
	if e != nil {
		if e != sql.ErrNoRows {
			return nil, nil, response.ErrInternal
		}
	}
	if payoutEx.BetId == 0 {
		payoutEx = nil
	}
	playMaxStep, e1 := dao.GetPlayMaxStep(betId)
	if e1 != nil {
		if e1 != sql.ErrNoRows {
			return nil, nil, response.ErrInternal
		}
	}
	if playMaxStep.BetId == 0 {
		playMaxStep = nil
	}

	return payoutEx, playMaxStep, 0
}

func (sv *StmSV) GetRouRound(roundId, instId int64) (*roulettep.RouletteRoundEntity, int16) {
	dao := admindao.RouDao{Driver: sv.rouDs.Ds()}
	ret, e := dao.GetRouRound(roundId, instId)
	if e != nil {
		if e != sql.ErrNoRows {
			return nil, response.ErrInternal
		}
		return nil, response.ErrNotFound
	}

	return ret, 0
}

func (sv *StmSV) GetRouNodeRound(nodeId, instId, roundId int64) (*roulettep.RouNodeRoundEntity, int16) {
	dao := admindao.RouDao{Driver: sv.rouDs.Ds()}
	ret, e := dao.GetRouNodeRound(nodeId, instId, roundId)
	if e != nil {
		if e != sql.ErrNoRows {
			return nil, response.ErrInternal
		}
		return nil, response.ErrNotFound
	}

	return ret, 0
}

func (sv *StmSV) GetBetsInToArr(ids string) ([]*statement.PlayBetEnt, int, int16) {
	dao := stmdao.StmDao{Driver: sv.stmDs.Ds()}
	ret, c, e := dao.GetPlayBetInToArr(ids)
	if e != nil {
		logger.Error("[StmSV] get bets list Error on GetPlayBetIn", zap.String("BetIds", ids), zap.Error(e))
		return nil, 0, response.ErrInternal
	}

	return ret, c, 0
}

func (sv *StmSV) RouRoundDraw(rd *roulettep.RouletteRoundEntity) int16 {
	dao := roudao.RouletteDao{Driver: sv.rouDs.Ds()}
	_, e := dao.ChangeToOpenState(rd)
	if e != nil {
		return response.ErrInternal
	}

	return 0
}

func (sv *StmSV) GetUserBets(adm *adc.Admin, req wzabind.WzUserBetsReq) ([]*model.BetHistory, int16) {
	dao := admindao.StmDao{Driver: sv.stmDs.Ds()}
	offset := (req.Page - 1) * req.PageSize
	ret, err := dao.GetWzUserBets(req, offset)
	if err != nil {
		if err != sql.ErrNoRows {
			logger.Error("[StmSV] get wz user bets Error on GetWzUserBets", zap.Int64("AdminId", adm.AdminId()), zap.Uint64("UserId", req.Uid), zap.Error(err))
			return nil, response.ErrInternal
		}
	}

	return ret, 0
}

func (sv *StmSV) GetUserBetTotal(adm *adc.Admin, req wzabind.WzUserBetsReq) (int, int16) {
	dao := admindao.StmDao{Driver: sv.stmDs.Ds()}
	ret, err := dao.GetWzUserBetTotal(req)
	if err != nil {
		logger.Error("[StmSV] get wz user bets count on GetWzUserBetTotal", zap.Int64("AdminId", adm.AdminId()), zap.Uint64("UserId", req.Uid), zap.Error(err))
		return 0, response.ErrInternal
	}

	return ret, 0
}

func (sv *StmSV) GetUserBetSum(adm *adc.Admin, req wzabind.WzUserBetsReq) (*model.BetSum, int16) {
	dao := admindao.StmDao{Driver: sv.stmDs.Ds()}
	ret, err := dao.GetWzUserBetSum(req)
	if err != nil {
		logger.Error("[StmSV] get wz user bets sum on GetWzUserBetSum", zap.Int64("AdminId", adm.AdminId()), zap.Uint64("UserId", req.Uid), zap.Error(err))
		return nil, response.ErrInternal
	}
	ret.BetAmt = response.TrimAmtZeros(ret.BetAmt)
	ret.EffAmt = response.TrimAmtZeros(ret.EffAmt)
	ret.WinAmt = response.TrimAmtZeros(ret.WinAmt)
	ret.Fee = response.TrimAmtZeros(ret.Fee)

	return ret, 0
}
